package munci.old.learn;

import java.lang.reflect.Method;

import munci.old.java.Type;
import munci.old.know.Env;
import munci.old.know.words.MetaWord;
import munci.old.know.words.MethodWord;
import munci.old.know.words.Word;
import munci.old.use.Tokens;


public class Generics {

	public static final Word[] WORDS =
		MetaWord.all(MethodWord.all(new Word.Book(Generics.class)))
			.toArray();
	
	@MethodWord.Compile("print") public static Tokens print(Tokens expr) {
		return new Tokens().lex("System.out.print(").addAll(expr).add(")");
	}

	@MethodWord.Name("print") public static void print(boolean val) {
		System.out.print(val);
	}
	
	@MethodWord.Name("print") public static void print(char val) {
		System.out.print(val);
	}
	
	@MethodWord.Name("print") public static void print(byte val) {
		System.out.print(val);
	}
	
	@MethodWord.Name("print") public static void print(short val) {
		System.out.print(val);
	}
	
	@MethodWord.Name("print") public static void print(int val) {
		System.out.print(val);
	}
	
	@MethodWord.Name("print") public static void print(long val) {
		System.out.print(val);
	}
	
	@MethodWord.Name("print") public static void print(float val) {
		System.out.print(val);
	}
	
	@MethodWord.Name("print") public static void print(double val) {
		System.out.print(val);
	}
	
	@MethodWord.Name("print") public static void print(Object val) {
		System.out.print(val);
	}
	
	@MethodWord.Name("print") public static void printArr(Object[] val) {
		for (Object obj : val) {
			System.out.println(obj);
		}
	}

	@MethodWord.Compile("+") public static Tokens add(Tokens a, Tokens b) {
		return binOp("+", a, b);
	}
	@MethodWord.Compile("-") public static Tokens sub(Tokens a, Tokens b) {
		return binOp("-", a, b);
	}
	@MethodWord.Compile("*") public static Tokens mul(Tokens a, Tokens b) {
		return binOp("*", a, b);
	}
	@MethodWord.Compile("/") public static Tokens div(Tokens a, Tokens b) {
		return binOp("/", a, b);
	}
	@MethodWord.Compile("%") public static Tokens mod(Tokens a, Tokens b) {
		return binOp("%", a, b);
	}
	@MethodWord.Compile("==") public static Tokens eq(Tokens a, Tokens b) {
		return binOp("==", a, b);
	}
	@MethodWord.Compile("!=") public static Tokens ne(Tokens a, Tokens b) {
		return binOp("!=", a, b);
	}
	@MethodWord.Compile("<") public static Tokens lt(Tokens a, Tokens b) {
		return binOp("<", a, b);
	}
	@MethodWord.Compile("<=") public static Tokens le(Tokens a, Tokens b) {
		return binOp("<=", a, b);
	}
	@MethodWord.Compile(">") public static Tokens gt(Tokens a, Tokens b) {
		return binOp(">", a, b);
	}
	@MethodWord.Compile(">=") public static Tokens ge(Tokens a, Tokens b) {
		return binOp(">=", a, b);
	}
	
	private static Tokens binOp(String op, Tokens a, Tokens b) {
		return new Tokens().add("(").addAll(a)
			.add(op).addAll(b).add(")");
	}

	@MethodWord.Name("+") public static int add(byte a, byte b) {return a + b;}
	@MethodWord.Name("+") public static int add(char a, char b) {return a + b;}
	@MethodWord.Name("+") public static int add(short a, short b) {return a + b;}
	@MethodWord.Name("+") public static int add(int a, int b) {return a + b;}
	@MethodWord.Name("+") public static long add(long a, long b) {return a + b;}
	@MethodWord.Name("+") public static float add(float a, float b) {return a + b;}
	@MethodWord.Name("+") public static double add(double a, double b) {return a + b;}
	
	@MethodWord.Name("-") public static int sub(byte a, byte b) {return a - b;}
	@MethodWord.Name("-") public static int sub(char a, char b) {return a - b;}
	@MethodWord.Name("-") public static int sub(short a, short b) {return a - b;}
	@MethodWord.Name("-") public static int sub(int a, int b) {return a - b;}
	@MethodWord.Name("-") public static long sub(long a, long b) {return a - b;}
	@MethodWord.Name("-") public static float sub(float a, float b) {return a - b;}
	@MethodWord.Name("-") public static double sub(double a, double b) {return a - b;}
	
	@MethodWord.Name("*") public static int mul(byte a, byte b) {return a * b;}
	@MethodWord.Name("*") public static int mul(char a, char b) {return a * b;}
	@MethodWord.Name("*") public static int mul(short a, short b) {return a * b;}
	@MethodWord.Name("*") public static int mul(int a, int b) {return a * b;}
	@MethodWord.Name("*") public static long mul(long a, long b) {return a * b;}
	@MethodWord.Name("*") public static float mul(float a, float b) {return a * b;}
	@MethodWord.Name("*") public static double mul(double a, double b) {return a * b;}
	
	@MethodWord.Name("/") public static int div(byte a, byte b) {return a / b;}
	@MethodWord.Name("/") public static int div(char a, char b) {return a / b;}
	@MethodWord.Name("/") public static int div(short a, short b) {return a / b;}
	@MethodWord.Name("/") public static int div(int a, int b) {return a / b;}
	@MethodWord.Name("/") public static long div(long a, long b) {return a / b;}
	@MethodWord.Name("/") public static float div(float a, float b) {return a / b;}
	@MethodWord.Name("/") public static double div(double a, double b) {return a / b;}
	
	@MetaWord.Name("cast") public static void cast(Env env) throws Exception {
		Type.Prim.Num type = (Type.Prim.Num) env.stack.pop();
		Method method = Number.class.getMethod(type.toString() + "Value");
		env.stack.push(method.invoke(env.stack.pop()), type.toClass(env.dict));
	}
	
	@MethodWord.Name("box") public static Boolean box(boolean val) {return val;}
	@MethodWord.Name("box") public static Character box(char val) {return val;}
	@MethodWord.Name("box") public static Byte box(byte val) {return val;}
	@MethodWord.Name("box") public static Short box(short val) {return val;}
	@MethodWord.Name("box") public static Integer box(int val) {return val;}
	@MethodWord.Name("box") public static Long box(long val) {return val;}
	@MethodWord.Name("box") public static Float box(float val) {return val;}
	@MethodWord.Name("box") public static Double box(double val) {return val;}
	
	@MethodWord.Name("unbox") public static boolean unbox(Boolean val) {return val;}
	@MethodWord.Name("unbox") public static char unbox(Character val) {return val;}
	@MethodWord.Name("unbox") public static byte unbox(Byte val) {return val;}
	@MethodWord.Name("unbox") public static short unbox(Short val) {return val;}
	@MethodWord.Name("unbox") public static int unbox(Integer val) {return val;}
	@MethodWord.Name("unbox") public static long unbox(Long val) {return val;}
	@MethodWord.Name("unbox") public static float unbox(Float val) {return val;}
	@MethodWord.Name("unbox") public static double unbox(Double val) {return val;}
}
